package accesslog

import (
	"fmt"
	"strings"
)

// List of supported command operators.
const (

	// Commands that support arguments and max length constraint.

	CMD_REQ              = "REQ"
	CMD_RESP             = "RESP"
	CMD_TRAILER          = "TRAILER"
	CMD_DYNAMIC_METADATA = "DYNAMIC_METADATA"
	CMD_FILTER_STATE     = "FILTER_STATE"
	CMD_START_TIME       = "START_TIME"

	// Commands that differ for HTTP and TCP log entries.

	CMD_BYTES_RECEIVED        = "BYTES_RECEIVED"
	CMD_BYTES_SENT            = "BYTES_SENT"
	CMD_PROTOCOL              = "PROTOCOL"
	CMD_RESPONSE_CODE         = "RESPONSE_CODE"
	CMD_RESPONSE_CODE_DETAILS = "RESPONSE_CODE_DETAILS"
	CMD_REQUEST_DURATION      = "REQUEST_DURATION"
	CMD_RESPONSE_DURATION     = "RESPONSE_DURATION"
	CMD_RESPONSE_TX_DURATION  = "RESPONSE_TX_DURATION"

	// Commands that are the same for HTTP and TCP log entries.

	CMD_DURATION                                      = "DURATION"
	CMD_RESPONSE_FLAGS                                = "RESPONSE_FLAGS"
	CMD_UPSTREAM_HOST                                 = "UPSTREAM_HOST"
	CMD_UPSTREAM_CLUSTER                              = "UPSTREAM_CLUSTER"
	CMD_UPSTREAM_LOCAL_ADDRESS                        = "UPSTREAM_LOCAL_ADDRESS"
	CMD_DOWNSTREAM_LOCAL_ADDRESS                      = "DOWNSTREAM_LOCAL_ADDRESS"
	CMD_DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT         = "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT"
	CMD_DOWNSTREAM_REMOTE_ADDRESS                     = "DOWNSTREAM_REMOTE_ADDRESS"
	CMD_DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT        = "DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT"
	CMD_DOWNSTREAM_DIRECT_REMOTE_ADDRESS              = "DOWNSTREAM_DIRECT_REMOTE_ADDRESS"
	CMD_DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT = "DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT"
	CMD_REQUESTED_SERVER_NAME                         = "REQUESTED_SERVER_NAME"
	CMD_ROUTE_NAME                                    = "ROUTE_NAME"
	CMD_DOWNSTREAM_PEER_URI_SAN                       = "DOWNSTREAM_PEER_URI_SAN"
	CMD_DOWNSTREAM_LOCAL_URI_SAN                      = "DOWNSTREAM_LOCAL_URI_SAN"
	CMD_DOWNSTREAM_PEER_SUBJECT                       = "DOWNSTREAM_PEER_SUBJECT"
	CMD_DOWNSTREAM_LOCAL_SUBJECT                      = "DOWNSTREAM_LOCAL_SUBJECT"
	CMD_DOWNSTREAM_TLS_SESSION_ID                     = "DOWNSTREAM_TLS_SESSION_ID"
	CMD_DOWNSTREAM_TLS_CIPHER                         = "DOWNSTREAM_TLS_CIPHER"
	CMD_DOWNSTREAM_TLS_VERSION                        = "DOWNSTREAM_TLS_VERSION"
	CMD_UPSTREAM_TRANSPORT_FAILURE_REASON             = "UPSTREAM_TRANSPORT_FAILURE_REASON"

	// Commands that are the same for HTTP and TCP log entries
	// but have no equivalent data in GrpcAccessLog.

	CMD_DOWNSTREAM_PEER_FINGERPRINT_256 = "DOWNSTREAM_PEER_FINGERPRINT_256"
	CMD_DOWNSTREAM_PEER_SERIAL          = "DOWNSTREAM_PEER_SERIAL"
	CMD_DOWNSTREAM_PEER_ISSUER          = "DOWNSTREAM_PEER_ISSUER"
	CMD_DOWNSTREAM_PEER_CERT            = "DOWNSTREAM_PEER_CERT"
	CMD_DOWNSTREAM_PEER_CERT_V_START    = "DOWNSTREAM_PEER_CERT_V_START"
	CMD_DOWNSTREAM_PEER_CERT_V_END      = "DOWNSTREAM_PEER_CERT_V_END"
	CMD_HOSTNAME                        = "HOSTNAME"

	// Commands unique to Kuma.

	CMD_KUMA_SOURCE_ADDRESS              = "KUMA_SOURCE_ADDRESS"
	CMD_KUMA_SOURCE_ADDRESS_WITHOUT_PORT = "KUMA_SOURCE_ADDRESS_WITHOUT_PORT"
	CMD_KUMA_SOURCE_SERVICE              = "KUMA_SOURCE_SERVICE"
	CMD_KUMA_DESTINATION_SERVICE         = "KUMA_DESTINATION_SERVICE"
	CMD_KUMA_MESH                        = "KUMA_MESH"
	CMD_KUMA_TRAFFIC_DIRECTION           = "KUMA_TRAFFIC_DIRECTION"
)

// CommandOperatorDescriptor represents a descriptor of an Envoy access log command operator.
//
// See https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log#command-operators
type CommandOperatorDescriptor string

// String returns the reference name of an Envoy access log command operator
// as it appears on https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log#command-operators
func (o CommandOperatorDescriptor) String() string {
	switch string(o) {
	case CMD_REQ:
		return "%REQ(X?Y):Z%"
	case CMD_RESP:
		return "%RESP(X?Y):Z%"
	case CMD_TRAILER:
		return "%TRAILER(X?Y):Z%"
	case CMD_DYNAMIC_METADATA:
		return "%DYNAMIC_METADATA(NAMESPACE:KEY*):Z%"
	case CMD_FILTER_STATE:
		return "%FILTER_STATE(KEY):Z%"
	case CMD_START_TIME:
		return "%START_TIME%"
	case CMD_BYTES_RECEIVED:
		return "%BYTES_RECEIVED%"
	case CMD_BYTES_SENT:
		return "%BYTES_SENT%"
	case CMD_PROTOCOL:
		return "%PROTOCOL%"
	case CMD_RESPONSE_CODE:
		return "%RESPONSE_CODE%"
	case CMD_RESPONSE_CODE_DETAILS:
		return "%RESPONSE_CODE_DETAILS%"
	case CMD_REQUEST_DURATION:
		return "%REQUEST_DURATION%"
	case CMD_RESPONSE_DURATION:
		return "%RESPONSE_DURATION%"
	case CMD_RESPONSE_TX_DURATION:
		return "%RESPONSE_TX_DURATION%"
	case CMD_DURATION:
		return "%DURATION%"
	case CMD_RESPONSE_FLAGS:
		return "%RESPONSE_FLAGS%"
	case CMD_UPSTREAM_HOST:
		return "%UPSTREAM_HOST%"
	case CMD_UPSTREAM_CLUSTER:
		return "%UPSTREAM_CLUSTER%"
	case CMD_UPSTREAM_LOCAL_ADDRESS:
		return "%UPSTREAM_LOCAL_ADDRESS%"
	case CMD_DOWNSTREAM_LOCAL_ADDRESS:
		return "%DOWNSTREAM_LOCAL_ADDRESS%"
	case CMD_DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT:
		return "%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%"
	case CMD_DOWNSTREAM_REMOTE_ADDRESS:
		return "%DOWNSTREAM_REMOTE_ADDRESS%"
	case CMD_DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT:
		return "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"
	case CMD_DOWNSTREAM_DIRECT_REMOTE_ADDRESS:
		return "%DOWNSTREAM_DIRECT_REMOTE_ADDRESS%"
	case CMD_DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT:
		return "%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT%"
	case CMD_REQUESTED_SERVER_NAME:
		return "%REQUESTED_SERVER_NAME%"
	case CMD_ROUTE_NAME:
		return "%ROUTE_NAME%"
	case CMD_DOWNSTREAM_PEER_URI_SAN:
		return "%DOWNSTREAM_PEER_URI_SAN%"
	case CMD_DOWNSTREAM_LOCAL_URI_SAN:
		return "%DOWNSTREAM_LOCAL_URI_SAN%"
	case CMD_DOWNSTREAM_PEER_SUBJECT:
		return "%DOWNSTREAM_PEER_SUBJECT%"
	case CMD_DOWNSTREAM_LOCAL_SUBJECT:
		return "%DOWNSTREAM_LOCAL_SUBJECT%"
	case CMD_DOWNSTREAM_TLS_SESSION_ID:
		return "%DOWNSTREAM_TLS_SESSION_ID%"
	case CMD_DOWNSTREAM_TLS_CIPHER:
		return "%DOWNSTREAM_TLS_CIPHER%"
	case CMD_DOWNSTREAM_TLS_VERSION:
		return "%DOWNSTREAM_TLS_VERSION%"
	case CMD_UPSTREAM_TRANSPORT_FAILURE_REASON:
		return "%UPSTREAM_TRANSPORT_FAILURE_REASON%"
	case CMD_DOWNSTREAM_PEER_FINGERPRINT_256:
		return "%DOWNSTREAM_PEER_FINGERPRINT_256%"
	case CMD_DOWNSTREAM_PEER_SERIAL:
		return "%DOWNSTREAM_PEER_SERIAL%"
	case CMD_DOWNSTREAM_PEER_ISSUER:
		return "%DOWNSTREAM_PEER_ISSUER%"
	case CMD_DOWNSTREAM_PEER_CERT:
		return "%DOWNSTREAM_PEER_CERT%"
	case CMD_DOWNSTREAM_PEER_CERT_V_START:
		return "%DOWNSTREAM_PEER_CERT_V_START%"
	case CMD_DOWNSTREAM_PEER_CERT_V_END:
		return "%DOWNSTREAM_PEER_CERT_V_END%"
	case CMD_HOSTNAME:
		return "%HOSTNAME%"
	case CMD_KUMA_SOURCE_ADDRESS:
		return "%KUMA_SOURCE_ADDRESS%"
	case CMD_KUMA_SOURCE_ADDRESS_WITHOUT_PORT:
		return "%KUMA_SOURCE_ADDRESS_WITHOUT_PORT%"
	case CMD_KUMA_SOURCE_SERVICE:
		return "%KUMA_SOURCE_SERVICE%"
	case CMD_KUMA_DESTINATION_SERVICE:
		return "%KUMA_DESTINATION_SERVICE%"
	case CMD_KUMA_MESH:
		return "%KUMA_MESH%"
	case CMD_KUMA_TRAFFIC_DIRECTION:
		return "%KUMA_TRAFFIC_DIRECTION%"
	default:
		return fmt.Sprintf("%%%s%%", string(o))
	}
}

// IsPlaceholder returns true if this command is a placeholder
// that must be resolved before configuring Envoy with that format string.
// E.g., %KUMA_SOURCE_ADDRESS%, %KUMA_SOURCE_ADDRESS_WITHOUT_PORT%,
// %KUMA_SOURCE_SERVICE% and %KUMA_DESTINATION_SERVICE%
// are examples of such placeholders.
func (o CommandOperatorDescriptor) IsPlaceholder() bool {
	return strings.HasPrefix(string(o), "KUMA_")
}
